/***********************************************************************************
 @file   
 @author
 @attention
 ***********************************************************************************/
#include "crc.h"

/***********************************************************************************
 * @brief  
***********************************************************************************/
const unsigned char chCRCHTalbe[] =                       // CRC 高位字节值表
{
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40
};

const unsigned char chCRCLTalbe[] =                          // CRC 低位字节值表
{
	0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04,
	0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8,
	0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,
	0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,
	0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
	0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,
	0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,
	0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,
	0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,
	0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
	0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,
	0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,
	0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
	0x9C,0x5C,0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,
	0x88,0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,
	0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40
};
const unsigned short crc16Table[CRC_TABLE_SIZE] = {
0x0000, 0x8005, 0x800F, 0x000A,
0x801B, 0x001E, 0x0014, 0x8011,
0x8033, 0x0036, 0x003C, 0x8039,
0x0028, 0x802D, 0x8027, 0x0022,
0x8063, 0x0066, 0x006C, 0x8069,
0x0078, 0x807D, 0x8077, 0x0072,
0x0050, 0x8055, 0x805F, 0x005A,
0x804B, 0x004E, 0x0044, 0x8041,
0x80C3, 0x00C6, 0x00CC, 0x80C9,
0x00D8, 0x80DD, 0x80D7, 0x00D2,
0x00F0, 0x80F5, 0x80FF, 0x00FA,
0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA,
0x80BB, 0x00BE, 0x00B4, 0x80B1,
0x8093, 0x0096, 0x009C, 0x8099,
0x0088, 0x808D, 0x8087, 0x0082,
0x8183, 0x0186, 0x018C, 0x8189,
0x0198, 0x819D, 0x8197, 0x0192,
0x01B0, 0x81B5, 0x81BF, 0x01BA,
0x81AB, 0x01AE, 0x01A4, 0x81A1,
0x01E0, 0x81E5, 0x81EF, 0x01EA,
0x81FB, 0x01FE, 0x01F4, 0x81F1,
0x81D3, 0x01D6, 0x01DC, 0x81D9,
0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A,
0x815B, 0x015E, 0x0154, 0x8151,
0x8173, 0x0176, 0x017C, 0x8179,
0x0168, 0x816D, 0x8167, 0x0162,
0x8123, 0x0126, 0x012C, 0x8129,
0x0138, 0x813D, 0x8137, 0x0132,
0x0110, 0x8115, 0x811F, 0x011A,
0x810B, 0x010E, 0x0104, 0x8101,
0x8303, 0x0306, 0x030C, 0x8309,
0x0318, 0x831D, 0x8317, 0x0312,
0x0330, 0x8335, 0x833F, 0x033A,
0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A,
0x837B, 0x037E, 0x0374, 0x8371,
0x8353, 0x0356, 0x035C, 0x8359,
0x0348, 0x834D, 0x8347, 0x0342,
0x03C0, 0x83C5, 0x83CF, 0x03CA,
0x83DB, 0x03DE, 0x03D4, 0x83D1,
0x83F3, 0x03F6, 0x03FC, 0x83F9,
0x03E8, 0x83ED, 0x83E7, 0x03E2,
0x83A3, 0x03A6, 0x03AC, 0x83A9,
0x03B8, 0x83BD, 0x83B7, 0x03B2,
0x0390, 0x8395, 0x839F, 0x039A,
0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A,
0x829B, 0x029E, 0x0294, 0x8291,
0x82B3, 0x02B6, 0x02BC, 0x82B9,
0x02A8, 0x82AD, 0x82A7, 0x02A2,
0x82E3, 0x02E6, 0x02EC, 0x82E9,
0x02F8, 0x82FD, 0x82F7, 0x02F2,
0x02D0, 0x82D5, 0x82DF, 0x02DA,
0x82CB, 0x02CE, 0x02C4, 0x82C1,
0x8243, 0x0246, 0x024C, 0x8249,
0x0258, 0x825D, 0x8257, 0x0252,
0x0270, 0x8275, 0x827F, 0x027A,
0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A,
0x823B, 0x023E, 0x0234, 0x8231,
0x8213, 0x0216, 0x021C, 0x8219,
0x0208, 0x820D, 0x8207, 0x0202
};





/********************************************************************
 函数功能: 获取一串行缓冲区数据的CRC校验值
 入口参数: CRCArray[],缓冲区名,ArrayLen缓冲区长度
 返回值  : CRCdata,经计算得出的CRC校验值
*********************************************************************/
unsigned short GetCRC(unsigned char CRCArray[],uint16_t ArrayLen)
{
	unsigned char chCRCH = 0xFF;						//高CRC字节初始化
	unsigned char chCRCL = 0xFF;						//低CRC字节初始化
	unsigned short i=0;									//数组下标用
	unsigned short wIndex;								//CRC循环中的索引
	while(ArrayLen--)									//计算CRC
	{
		wIndex = chCRCL ^ CRCArray[i++];
		chCRCL = chCRCH ^ chCRCHTalbe[wIndex]; 
		chCRCH = chCRCLTalbe[wIndex] ;
	}
	return (chCRCL<<8)|chCRCH;
}

/********************************************************************
 函数功能：串口检查CRC校验位函数，校验数据是否正确，PAddr(包含)到CRC
           之前的数据
 入口参数：无
 返回值  ：CRCOK，校验通过(1)，校验不通过(0)
*********************************************************************/
unsigned char checkCRC(unsigned char CRCArray[],uint16_t ArrayLen)
{
	unsigned char CRCOK;
	unsigned short CRCdata;
	CRCdata=(CRCArray[ArrayLen-2]<<8)+CRCArray[ArrayLen-1];//数组后两个字节组成CRC数据
	CRCOK=(CRCdata==GetCRC(CRCArray,ArrayLen-2))?1:0;		
	return CRCOK;
}




/********************************************
*    输入参数：
*    *pchMsg:     指向计算验证码的内存序列首址；
*    wDataLen:    序列长度；
*    返回值：
*    uint16_t:    计算后的验证码；
********************************************/
uint16_t  CRC16_TCP(uint8_t *pchMsg, uint16_t  wDataLen)
{
    uint16_t wCRC = 0xFFFF;
    uint8_t i, chChar;
    while (wDataLen--)
    {
        chChar = *pchMsg++;
        wCRC ^= (((uint16_t) chChar) << 8);
        for (i = 0; i< 8; i++)
        {
            if (wCRC& 0x8000)
                wCRC = (wCRC<< 1) ^ CRC_16_POLYNOMIALS;
            else
                wCRC<<= 1;
        }
    }
    return wCRC;
}

/********************************************
*    输入参数：
*    *pchMsg:     指向计算验证码的内存序列首址；
*    wDataLen:    序列长度；
*    返回值：
*    uint16_t:    计算后的验证码；
********************************************/
unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{
    unsigned short wCRCin = 0x0000;
    unsigned short wCPoly = 0x1021;
    unsigned char wChar = 0;
    while (usDataLen--)
    {
        wChar = *(puchMsg++);
        wCRCin ^= (wChar << 8);
        for (int i = 0; i < 8; i++)
        {
            if (wCRCin & 0x8000)
                wCRCin = (wCRCin << 1) ^ wCPoly;
            else
                wCRCin = wCRCin << 1;
        }
    }
    return (wCRCin);
}

/***********************************************************************************
 * @brief  
 * @param 
 * @retval 
***********************************************************************************/
uint8_t crc_16_CCITT_False(uint8_t * pucFrame,uint8_t offset ,uint8_t usLen) 
{
	int start = offset; //选择数据要计算CRC的起始位
	int end = offset + usLen; //选择数据要CRC计算的范围段
 
	unsigned short  crc = 0xffff; // initial value
	unsigned short  polynomial = 0x1021; // poly value
	for (int index = start; index < end; index++) 
	{
		uint8_t b = pucFrame[index];
		for (int i = 0; i < 8; i++) {
			uint8_t bit = ((b >> (7 - i) & 1) == 1);
			uint8_t c15 = ((crc >> 15 & 1) == 1);
			crc <<= 1;
			if (c15 ^ bit)
				crc ^= polynomial;
		}
	}
	crc &= 0x00ff;
	return crc;
}
/***********************************************************************************
 * @brief  
 * @param 
 * @retval 
***********************************************************************************/
unsigned short crc16MakeTableMethod(unsigned char *pbuffer, unsigned int length)
{
    uint16_t crc=CRC16_INIT_REM;
    while(length--)
    {
    crc = crc16Table[((crc >> 8) ^ *pbuffer++)] ^ (crc << 8);
    }
    return (crc ^ CRC16_FINAL_XOR);
}
